//School of Informatics Xiamen University, GPL-3.0 license
package cn.edu.xmu.javaee.productdemo.controller;

import cn.edu.xmu.javaee.productdemo.service.vo.ProductVo;
import cn.edu.xmu.javaee.productdemo.dao.bo.Product;
import cn.edu.xmu.javaee.core.exception.BusinessException;
import cn.edu.xmu.javaee.core.model.ReturnNo;
import cn.edu.xmu.javaee.productdemo.controller.dto.ProductDto;
import cn.edu.xmu.javaee.productdemo.service.ProductService;
import cn.edu.xmu.javaee.core.model.ReturnObject;
import cn.edu.xmu.javaee.core.util.JacksonUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 商品控制器
 * @author Ming Qiu
 */
@RestController
@RequestMapping(value = "/shops/{shopId}", produces = "application/json;charset=UTF-8")
@Slf4j
@RequiredArgsConstructor
public class AdminProductController{

    private final ProductService productService;
    private final MessageSource messageSource;

    /**
     * 商铺管理员申请增加新的Product
     * @param shopId
     * @return
     */
    @PostMapping("/products")
    @ResponseStatus(HttpStatus.CREATED)
    public ReturnObject createDraft(@PathVariable Long shopId,
                                    @RequestBody ProductDto dto) {
        Locale locale = LocaleContextHolder.getLocale();
        log.debug("createDraft: dto = {}, locale = {}",dto, locale);
        Product newDraft = Product.builder().name(dto.getName()).originalPrice(dto.getOriginalPrice()).originPlace(dto.getOriginPlace()).categoryId(dto.getCategoryId()).build();
        newDraft.setShopId(shopId);
        ProductVo draft = this.productService.createDraft(newDraft);
        return new ReturnObject(ReturnNo.CREATED, messageSource.getMessage(ReturnNo.CREATED.getMessage(), null, locale), draft);
    }

    /**
     * 管理员或店家物理删除审核中的Products
     * @param shopId
     * @param id
     * @return
     */
    @GetMapping("/products/{id}")
    public ReturnObject getProducts(@PathVariable Long shopId, @PathVariable Long id, HttpServletResponse response){
        Locale locale = LocaleContextHolder.getLocale();
        log.debug("getProducts: shopId = {}, id = {}, locale = {}",shopId, id,locale);
        ProductVo draft;
        try {
            draft = this.productService.getDraft(shopId, id);
        }catch (BusinessException e){
            if (e.getErrno() == ReturnNo.RESOURCE_ID_NOTEXIST){
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            }else if (e.getErrno() == ReturnNo.RESOURCE_ID_OUTSCOPE){
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            }
            String message = getI18nMessage(e, locale);
            return new ReturnObject(e.getErrno(), message);
        }

        return new ReturnObject(ReturnNo.OK, messageSource.getMessage(ReturnNo.OK.getMessage(), null, locale), draft);
    }


    /**
     * 管理员或店家物理删除审核中的Products
     * @param shopId
     * @param id
     * @return
     */
    @DeleteMapping("/products/{id}")
    public ReturnObject delProducts(@PathVariable Long shopId, @PathVariable Long id, HttpServletResponse response){
        Locale locale = LocaleContextHolder.getLocale();
        try {
            this.productService.delDraft(shopId, id);
        }catch (BusinessException e){
            if (e.getErrno() == ReturnNo.RESOURCE_ID_NOTEXIST){
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            }else if (e.getErrno() == ReturnNo.RESOURCE_ID_OUTSCOPE){
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            }
            String message = getI18nMessage(e, locale);
            return new ReturnObject(e.getErrno(), message);
        }
        return new ReturnObject(ReturnNo.OK, messageSource.getMessage(ReturnNo.OK.getMessage(), null, locale));
    }

    /**
     * 管理员或店家修改审核中的Products
     * @param shopId
     * @param id
     * @param vo
     * @return
     */
    @PutMapping("/products/{id}")
    public ReturnObject modifyDraft(@PathVariable Long shopId, @PathVariable Long id, @RequestBody ProductDto vo, HttpServletResponse response){
        Locale locale = LocaleContextHolder.getLocale();
        Product updateDraft = Product.builder().name(vo.getName()).originalPrice(vo.getOriginalPrice()).originPlace(vo.getOriginPlace()).categoryId(vo.getCategoryId()).build();
        updateDraft.setId(id);
        try {
            this.productService.updateDraft(shopId, updateDraft);
        }catch (BusinessException e){
            if (e.getErrno() == ReturnNo.RESOURCE_ID_NOTEXIST){
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            }else if (e.getErrno() == ReturnNo.RESOURCE_ID_OUTSCOPE){
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            }
            String message = getI18nMessage(e, locale);
            return new ReturnObject(e.getErrno(), message);
        }
        return new ReturnObject(ReturnNo.OK, messageSource.getMessage(ReturnNo.OK.getMessage(), null, locale));
    }

    /**
     * 获得国际化的message
     * @param e 错误Exception
     * @return 国际化的信息
     */
    private String getI18nMessage(BusinessException e, Locale locale) {
        String message = e.getMessage();
        String errMsg = e.getErrno().getMessage();
        if (Objects.isNull(message)) {
            message = messageSource.getMessage(errMsg, null, locale);
        }else{
            Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
            List<String> args = JacksonUtil.parseObjectList(message, String.class).stream().map(arg -> {
                Matcher matcher = pattern.matcher(arg);
                String parsedArg = arg;
                if (matcher.find()) {
                    parsedArg =  this.messageSource.getMessage(matcher.group(1), null, locale);
                }
                return parsedArg;
            }).collect(Collectors.toList());
            message = this.messageSource.getMessage(errMsg, args.toArray(), locale);
        }
        return message;
    }
}
